<?php
/**
 * Created by PhpStorm.
 * User: caoyong
 * Date: 15/3/19
 * Time: 20:11
 */

namespace Caoyong\PHPCore;

use \Exception;

class Object
{
    /**
     * @return string
     */
    public static function className()
    {
        return get_called_class();
    }


    /**
     * @param $name
     * @return mixed
     *
     * @throws Exception
     */
    public function __get($name)
    {
        $getter = 'get'.$name;

        if ($this->hasMethod($getter)) {
            return $this->$getter();
        } elseif (method_exists($this, 'set'.$getter)) {
            throw new Exception("Getting write-only property: " . get_class($this) . "::" . $name);
        } else {
            throw new Exception("Getting unknown property: " . get_class($this) . "::" . $name);
        }
    }

    /**
     * @param $name string
     * @param $value mixed
     * @throws Exception
     * @throws Exception
     */
    public function __set($name, $value)
    {
        $setter = 'set' . $name;
        if ($this->hasMethod($setter)) {
            $this->$setter($value);
        } elseif ($this->hasMethod('get' . $name)) {
            throw new Exception('Setting read-only property: ' . get_class($this) . '::' . $name);
        } else {
            throw new Exception('Setting unknown property: ' . get_class($this) . '::' . $name);
        }
    }

    /**
     * @param $name
     * @return bool
     */
    public function __isset($name)
    {
        $getter = 'get' . $name;
        if ($this->hasMethod($getter)) {
            return $this->$getter() !== null;
        } else {
            return false;
        }
    }

    /**
     * @param $name
     * @throws Exception
     */
    public function __unset($name)
    {
        $setter = 'set' . $name;
        if ($this->hasMethod($setter)) {
            $this->$setter(null);
        } elseif (method_exists($this, 'get' . $name)) {
            throw new Exception('Unsetting read-only property: ' . get_class($this) . '::' . $name);
        }
    }

    public function __call($name, $args)
    {
        throw new Exception('Call unknown method: ' . get_class($this) . '::' . $name);
    }

    /**
     * @param $name
     * @return bool
     */
    public function hasMethod($name)
    {
        return method_exists($this, $name);
    }

    /**
     * @param $name
     * @return bool
     */
    public function hasProperty($name)
    {
        return $this->hasMethod('get' . $name) || $this->hasMethod('set' . $name);
    }
}
